package com.liveinstars.im.handler;

import com.liveinstars.im.entity.Msg;
import com.liveinstars.im.core.Session;
import com.liveinstars.im.core.SessionManager;
import com.liveinstars.im.corebean.MsgHelper;
import com.liveinstars.im.corebean.PingMessage;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.ReferenceCountUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

/**
 * 1、保持服务器间的心态 2、转发消息
 * 
 * @author ting
 *
 */
@Sharable
@Service
public class PingHandler extends SimpleChannelInboundHandler<PingMessage> {

	private static final Logger LOGGER = LoggerFactory.getLogger(PingHandler.class);
	@Autowired
	private SessionManager sessionManager;

	@Value("${netty.server.id}")
	public Long chatServerId;

	@Value("${netty.server.ip}")
	public String ip;

	@Value("${netty.server.outip}")
	public String outIp;

	@Value("${netty.server.port}")
	public Integer port;

	@Value("${netty.server.name}")
	public String chatServerName;

	@Override
	public void channelInactive(ChannelHandlerContext ctx) throws Exception {
		// channel失效，从Map中移除
		LOGGER.info("channelInactive");
		sessionManager.remove(ctx.channel().id().toString());
	}



	@Override
	public void userEventTriggered(ChannelHandlerContext ctx, Object evt)
			throws Exception {
		if (evt instanceof IdleStateEvent) {
			IdleStateEvent event = (IdleStateEvent) evt;
			if (event.state().equals(IdleState.READER_IDLE)) {
				LOGGER.info("READER_IDLE");
				// 超时关闭channel
				ctx.close();
				sessionManager.remove(ctx.channel().id().toString());
			} else if (event.state().equals(IdleState.WRITER_IDLE)) {
				LOGGER.info("WRITER_IDLE");
				sendPing(ctx);
			} else if (event.state().equals(IdleState.ALL_IDLE)) {
				LOGGER.info("ALL_IDLE");
				// 发送心跳
				sendPing(ctx);
			}
		}

	}

	/**
	 * 当出现WRITER_IDLE、ALL_IDLE时则需要向客户端发出ping消息，试探远端是否还在
	 */
	private void sendPing(ChannelHandlerContext ctx) {
		Session session = SessionManager.get(ctx.channel().id().toString());
		if (session != null) {
			Msg.Message ping = MsgHelper.newPingMessage(
					Msg.MessageType.SERVER_PING, ip + ":" + port);
			session.send(ping);
		}

	}

	@Override
	protected void channelRead0(ChannelHandlerContext channelHandlerContext,
			PingMessage message) throws Exception {

		switch (message.getMessageType()) {

		case SERVER_PING:
//			LOGGER.info("PingHandler get server ping。");
				sessionManager.serverPing(channelHandlerContext, message);
			break;
		case SERVER_PONG:
//			LOGGER.info("PingHandler get server pong msg: {}", message.toString());
			// 啥也不做
			break;
		case CLIENT_PING:
//			LOGGER.info("client ping {}", message.getClientId());
			Session session = sessionManager.clientAuth(channelHandlerContext.channel().id().toString());
			if (session != null) {
				sessionManager.clientPing(session);
			} else {
				Msg.Message rtMessage = MsgHelper.newResultMessage(
						Msg.MessageType.AUTH_ERROR, "用户认证失败，重新认证!");

				LOGGER.info("auth fail {}", message.getClientId());
				channelHandlerContext.channel().writeAndFlush(rtMessage);
				return;
			}
			break;
		case CLIENT_PONG:
//			LOGGER.info("PingHandler get client pong", message.toString());
			// 啥也不做
			break;

		default:
			break;
		}
		ReferenceCountUtil.release(message);
	}
}